#!/usr/bin/env python3
# coding: utf-8
# File: GraphShow.py


"""创建展示页面"""
import json


class GraphShow():
    def __init__(self):
        self.base = """
    <!DOCTYPE html>
<meta charset="utf-8">
<title>力导向图</title>
<style>

    .node {
        cursor: pointer;
        stroke: #3182bd;
        stroke-width: 1.5px;
    }

    .link {
        fill: none;
        stroke: #9ecae1;
        stroke-width: 1.5px;
    }

</style>
<body style="overflow-x: hidden ;overflow-y: hidden">
<script src="VIS/dist/d3.v3.min.js"></script>
<script>

    var width = 1560,
        height = 800,
        root;

    var force = d3.layout.force()
        // .size([width, height])
        // .on("tick", tick);
        .size([width, height])//作用域的大小
        .linkDistance(150)//连接线长度
        .charge(-1500)//顶点的电荷数。该参数决定是排斥还是吸引，数值越小越互相排斥
        .friction(0.9)
        .on("tick", tick)//指时间间隔，隔一段时间刷新一次画面
        .start();//开始转换
    var zoom = d3.behavior.zoom()//缩放配置，
        .scaleExtent([0.4, 2])//缩放比例
        .on("zoom", zoomed);

    function zoomed() {//缩放函数
// .selectAll("g")
        svg.selectAll("g").attr("transform",//svg下移动大小
            //
            "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
        /*console.log(d3.event.translate+"/"+d3.event.scale);*/
    }

    var svg = d3.select("body").append("svg")
        .attr("pointer-event", "all")
        // .attr("width", width)
        // .attr("height", height);
        .attr("preserveAspectRatio", "xMidYMid meet")
        .attr("viewBox", "0 0 1920 1000")
        .style('background-color','#fafbfc')
        // .append("g")
        .call(zoom)


    //添加标记以表明这是一个有向图
    svg.append("g").append("defs").selectAll("marker")
        .data(["arrow"])
        .enter().append("marker")
        .attr("id", function (d) {
            return d;
        })
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 25)
        .attr("refY", -1)
        .attr("markerWidth", 10)
        .attr("markerHeight", 12)
        .attr("orient", "auto")
        .append("path")
        .attr("stroke-width", 2)//箭头宽度
        .attr("d", "M0,-5L10,0L0,5")
        .attr('fill', '#C0C0C0');//箭头颜色;

    // svg.append("defs").append("g").selectAll(".edgepath")
    var link = svg.append("g").selectAll(".link"),
        node = svg.append("g").selectAll(".node");
    var svg_text = svg.append("g").selectAll('text');
    // var svg_edgepath = svg.selectAll(".edgepath");
    jsontest = {
        "nodes": data_nodes
        ,
        "links": data_edges


    }
    jsonmethod(jsontest);

    function jsonmethod(json) {
        // d3.json("graph.json", function (json) {
        root = jsontest;
        // root = json;
        //给出节点id和初始化变量
        for (var i = 0; i < root.nodes.length; i++) {
            var node = root.nodes[i];
            // node.id = i;
            node.id = root.nodes[i].id;
            // console.log(root.nodes[i].name)
            node.name = root.nodes[i].label
            node.collapsing = 0;
            node.collapsed = false;
        }
        //给出链接id和初始化变量
        for (var i = 0; i < root.links.length; i++) {
            var link = root.links[i];
            link.source = root.nodes[link.source];
            link.target = root.nodes[link.target];
            link.id = i;
        }

        update();

    }

    function update() {
        //只保留可见的节点
        var nodes = root.nodes.filter(function (d) {
            return d.collapsing === 0;
        });
        var links = root.links;
        //只保留可见的链接
        links = root.links.filter(function (d) {
            return d.source.collapsing === 0 && d.target.collapsing === 0;
        });

        force
            .nodes(nodes)
            .links(links)
            .start();

        // Update the links…
        link = link.data(links, function (d) {
            return d.id;
        });
        // link.enter().append("g").append("circle")

        // Exit any old links.
        link.exit().remove();

        // Enter any new links.
        link.enter().insert("line", ".node")
            .attr("class", "link")
            .attr("x1", function (d) {
                return d.source.x;
            })
            .attr("y1", function (d) {
                return d.source.y;
            })
            .attr("x2", function (d) {
                return d.target.x;
            })
            .attr("y2", function (d) {
                return d.target.y;
            })
            .attr("marker-end", "url(#arrow)");

        // Update the nodes…
        node = node.data(nodes, function (d) {
            return d.id;
        });

        // Exit any old nodes.
        node.exit().remove();

        // Enter any new nodes.
        node.enter().append("circle")
            .attr("class", "node")
            .attr("cx", function (d) {
                return d.x;
            })
            .attr("cy", function (d) {
                return d.y;
            })
            .attr("r", function (d) {
                // return Math.sqrt(d.size) / 10 || 4.5;
                return Math.sqrt(d.size) / 10 || 25;
            })
            // .style("fill", color)
            .style("fill", function (node) {
                var color;//圆圈背景色
                var link = links[node.index];
                if (node.group === "知识图谱") {
                    color = "#fd8d3c"
                    // } else if (node.group === "关键词"){|| node.group === "高频词" || node.group === "地名" || node.group === "人物" || node.group === "组织机构") {
                } else if (node.group === "关键词") {
                    color = "#fafbfc";
                } else if (node.group === "人物") {
                    color = "#fafbfc";
                } else if (node.group === "机构") {
                    color = "#fafbfc";
                } else if (node.group === "地名") {
                    color = "#fafbfc";
                } else if (node.group === "高频词") {
                    color = "#fafbfc";
                } else {
                    color = "#97c2fc";
                }
                return color;
            })
            .on("click", click)
            // .attr("r", 25)//设置圆圈半径
            // .attr('dominant-baseline', 'middle')
            .call(force.drag);
        svg_text = svg_text.data(nodes, function (d) {
            return d.name;
        })
        svg_text.exit().remove();


        // text
        svg_text.enter()
            // .append("g")
            .append('text')
            // .style('fill', '#000')
            .attr('dominant-baseline', 'middle')
            .attr('text-anchor', 'middle')
            .style('fill', function (node) {
                var color;//文字颜色
                color = "#000"
                return color;
            })
            .text(function (d) {
                return d.name
            });
        svg.on("dblclick.zoom", null);
        svg_text
            .attr('x', function (d) {
                return d.x
            })
            .attr('y', function (d) {
                return d.y
            })
            .attr('dominant-baseline', 'middle')
            .attr('text-anchor', 'middle')
            .text(function (d) {
                return d.name
            });
    }

    function tick() {
        link.attr("x1", function (d) {
            return d.source.x;
        })
            .attr("y1", function (d) {
                return d.source.y;
            })
            .attr("x2", function (d) {
                return d.target.x;
            })
            .attr("y2", function (d) {
                return d.target.y;
            });

        node.attr("cx", function (d) {
            return d.x;
        })
            .attr("cy", function (d) {
                return d.y;
            });
        svg_text
            .attr('x', function (d) {
                return d.x
            })
            .attr('y', function (d) {
                return d.y
            });
    }


    // 将叶子节点涂成橙色，包裹为白色或蓝色 .
    // function color(d) {
    //     return d.collapsed ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
    // }

    Array.prototype.del = function (index) {
        if (isNaN(index) || index >= this.length) {
            return false;
        }
        for (var i = 0; n = 0; i++) {
            if (this[i] != this[index]) {
                this[n++] = this[i];
            }
        }
        this.length -= 1;
    }
    //递归处理所有子节点 falg true ++ false --
    var tmpLink = []

    function recursion(d, data, flag) {
        if (data.length > 0) {
            data.forEach(el => {
                if (flag) {
                    //折叠记录
                    if (typeof (el['_nodeId']) == 'undefined') {
                        el['_nodeId'] = []
                    }
                    el['_nodeId'].push(d.id)
                } else {
                    //删除记录
                    if (el['_nodeId']) {
                        el['_nodeId'].del(el['_nodeId'].indexOf(d.id))
                    }
                }
                flag ? el.target.collapsing++ : el.target.collapsing--
                tmpLink.push(el.target.id)
                var tmp = root.links.filter(e => e.source.id === el.target.id && el.target.id !== d.id)
                tmp = tmp.filter(el => {
                    var a = tmpLink.find(e => e == el.target.id)
                    return a ? false : true
                })
                if (!flag) {
                    tmp = tmp.filter(el => {
                        return typeof (el['_nodeId']) != 'undefined' && el._nodeId.filter(e => e == d.id).length > 0
                    })
                } else {
                    tmp = tmp.filter(el => {
                        var a = root.nodes.find(e => e.id == el.target.id)
                        return a.collapsing == 0
                    })
                }
                recursion(d, tmp, flag)
            })
        }

    }

    // 在点击中切换孩子.
    function click(d) {
        console.log("click节点", d)
        if (!d3.event.defaultPrevented) {
            //过滤 sourceId 为 点击节点的 links 数组
            var relevantLinks = root.links.filter(el => el.source.id === d.id)
            if (d.collapsed) {
                //显示处理
                relevantLinks = relevantLinks.filter(el => {
                    return typeof (el['_nodeId']) != 'undefined' && el._nodeId.filter(e => e == d.id).length > 0
                })
                tmpLink = [d.id]
                recursion(d, relevantLinks, false)
            } else {
                //折叠处理
                relevantLinks = relevantLinks.filter(el => {
                    var a = root.nodes.find(e => e.id == el.target.id)
                    return a.collapsing == 0
                })
                tmpLink = [d.id]
                recursion(d, relevantLinks, true)
            }
            d.collapsed = !d.collapsed;
        }

        console.log("结果", root)
        update();
    }

</script>
    """

    """读取文件数据"""

    def create_page(self, events):
        nodes = []
        for event in events:
            nodes.append(event[0])
            nodes.append(event[1])
        node_dict = {node: index for index, node in enumerate(nodes)}

        data_nodes = []
        data_edges = []
        """抽取保存6大属性赋值标题"""
        # 关键字
        key_words = ""
        # 高频词
        used_word = ""
        # 人物
        person = ""
        # 机构
        organization = ""
        # 地名
        place_name = ""

        # 存放所有信息的数组
        allstar = []
        for node, id in node_dict.items():
            data = {}
            if node == "关键词":
                key_words = id
                data["group"] = "关键词"
                data["id"] = id
                data["label"] = node
            elif node == "高频词":
                used_word = id
                data["group"] = "高频词"
                data["id"] = id
                data["label"] = node
            elif node == "人物":
                person = id
                data["group"] = "人物"
                data["id"] = id
                data["label"] = node
            elif node == "机构":
                organization = id
                data["group"] = "机构"
                data["id"] = id
                data["label"] = node
            elif node == "地名":
                place_name = id
                data["group"] = "地名"
                data["id"] = id
                data["label"] = node
            else:
                data["group"] = "Event"
                data["id"] = id
                data["label"] = node
            data_nodes.append(data)

        # 做非空判断，追加数据

        if key_words != "":
            allstar.append(key_words)
        if used_word != "":
            allstar.append(used_word)
        if person != "":
            allstar.append(person)
        if organization != "":
            allstar.append(organization)
        if place_name != "":
            allstar.append(place_name)

        for edge in events:
            data = {}
            data["from"] = node_dict.get(edge[0])
            data["label"] = ""
            data["to"] = node_dict.get(edge[1])
            data_edges.append(data)


        all_node = []
        data_nodes.sort(key=lambda x: x["id"])
        for indexs in enumerate(data_nodes):
            data = {}
            data['node_id'] = data_nodes[indexs[0]]["id"]
            data['index'] = indexs[0]

            data_nodes[indexs[0]].update(id=indexs[0])
            all_node.append(data)

        # 获取最新的二级节点ID
        atleast_star = []

        # 最新 主题ID
        # the_theme_id = ""

        for node in data_nodes:
            if node.get("label") == '关键词':
                atleast_star.append(node.get("id"))
            if node.get("label") == '高频词':
                atleast_star.append(node.get("id"))
            if node.get("label") == '人物':
                atleast_star.append(node.get("id"))
            if node.get("label") == '地名':
                atleast_star.append(node.get("id"))
            if node.get("label") == '机构':
                atleast_star.append(node.get("id"))
        for edge in data_edges:
            for node in all_node:
                if node['node_id'] == edge.get("from"):
                    edge['from'] = node['index']
                if node['node_id'] == edge.get("to"):
                    edge['to'] = node['index']

        data_edges.sort(key=lambda x: x["from"])
        # print(str(data_edges))
        # # 遍历改变核心词关系走向
        for edge in data_edges:
            for star in atleast_star:
                if edge.get("to") == star:
                    A = edge['to']
                    B = edge['from']
                    edge['from'] = A
                    edge['to'] = B
        for edge in data_edges:
            edge["source"] = edge.pop("from")
            edge["target"] = edge.pop("to")
        # 创建html页面d
        self.create_html(data_nodes, data_edges)
        # print(data_nodes, data_edges)
        return data_nodes, data_edges

    """生成html文件"""

    def create_html(self, data_nodes, data_edges):
        f = open("graph_show.html", "w+", encoding="utf-8")
        html = self.base.replace("data_nodes", str(data_nodes)).replace("data_edges", str(data_edges))

        f.write(html)
        f.close()
